/* 
 * File:   SoClean Main.c
 * Author: Cody
 *
 * Created on December 31, 2012, 12:59 PM
 */

#include <p18f25k20.h>
#include <stdio.h>
#include <stdlib.h>
#include "Delays.h"
#include "Initializations.h"
#include "globals.h"
#include "Nokia_LCD_controls.h"
#include "SPI_Functions.h"
#include "section_test.h"
#include "System_Functions.h"
#include "Debug_Menu.h"
#include "Williams_time_numbers_framed.h"




#pragma config IESO = OFF           //Oscillator switchover disabled
#pragma config FOSC = INTIO67       //Internal RC oscillator with RA6 and RA7 as port functions
//#pragma config FOSC = INTIO7        //Oscillator is Internal RC with clock out on RA6
#pragma config FCMEN = OFF          //Fail safe clock monitor disabled
#pragma config BOREN = OFF          //No brown out reset
#pragma config PWRT = OFF           //Power up timer disabled
#pragma config WDTEN = OFF          //No Watchdog Timer
#pragma config PBADEN = OFF         //PortB configured as digital IO on reset
//#pragma config MCLRE = ON           //MCLR is enabled
#pragma config MCLRE = OFF           //MCLR is disabled
#pragma config LVP = OFF            //No low voltage programming!!!!








/* Function prototypes */
int main(void);
void interrupt interrupt_handler(void);


/* Global variables for Main */
bit dummy = 0;
bit man_pressed = 0;



/*
 * 
 */
int main(void) {

    oscillator_init();
    port_init();
    

    LCD_RESET = 1;

    milliseconds(1000);      //wait a really long time, in case the problem is
                            // with the power supply not being settled before
                            // I do EEPROM stuff



    //If the EEPROM 'keys' have been programmed properly, then
    //  the rest of the EEPROM data is now valid.
    /*  Had to do this because I couldn't find a way to tell the EEPROM
         to program to all 0's.  Instead it programmed to all F's.  That
         caused the run-time minutes to be an indeterminate number on first
         start up, and start time was 11:59 pm*/
    //Initialize everything from the stored EEPROM values!
    if(EEPROM_read(KEY_DATA1) == 0x06 && EEPROM_read(KEY_DATA2) == 0x13)
    {
        runtime_minutes_global = EEPROM_read(RUN_TIME_ADDR);
        start_time_minutes_global = EEPROM_read(START_TIME_ADDRL);
        milliseconds(5);    //in case the problem was the quick consecutive reads
                            //  and the adding and shifting
        start_time_minutes_global = start_time_minutes_global + ((EEPROM_read(START_TIME_ADDRH) << 8) & 0xFF00);
        LCD_invert = EEPROM_read(LCD_INVERT_ADDR);
        LCD_contrast = EEPROM_read(LCD_CONTRAST_ADDR);
        LCD_bias_system = EEPROM_read(LCD_BIAS_SYSTEM_ADDR);
        backlight_seconds_count = EEPROM_read(LCD_BACKLIGHT_TIME_ADDR);
        LCD_tempco = EEPROM_read(LCD_TEMPCO_ADDR);

        filter_minutes_count = EEPROM_read(FILTER_MINUTES_COUNT_L);
        milliseconds(5);
        filter_minutes_count = filter_minutes_count + ((EEPROM_read(FILTER_MINUTES_COUNT_H)<<8));

        hours_24 = EEPROM_read(HOURS_24_ADDR);
    }
    else
    {
        EEPROM_write_with_check(KEY_DATA1, 0x06);
        EEPROM_write_with_check(KEY_DATA2, 0x13);
        EEPROM_write_with_check(RUN_TIME_ADDR, 0x07);
        EEPROM_write_with_check(START_TIME_ADDRL, 0x58);
        EEPROM_write_with_check(START_TIME_ADDRH, 0x02);
        EEPROM_write_with_check(LCD_INVERT_ADDR, 0x00);
        EEPROM_write_with_check(LCD_CONTRAST_ADDR, 0xBA);
        EEPROM_write_with_check(LCD_BIAS_SYSTEM_ADDR, 0x04);
        EEPROM_write_with_check(LCD_BACKLIGHT_TIME_ADDR, 0x05);
        EEPROM_write_with_check(LCD_TEMPCO_ADDR, 0x01);
        EEPROM_write_with_check(FILTER_MINUTES_COUNT_H, 0x00);
        EEPROM_write_with_check(FILTER_MINUTES_COUNT_L, 0x00);
        EEPROM_write_with_check(HOURS_24_ADDR, 0x00);
    }

    //This is just another safety catch.  If the re-read EEPROM value
    //  is greater than 19 (which is what is causing the gibberish), then
    //  force it to be the max value, which is 19
    if(runtime_minutes_global > MAX_RUNTIME)
    {
        runtime_minutes_global = MAX_RUNTIME;
    }

    //This is a work-around to the "black screen" issue that
    //  they are seeing in the quality tests.  This is just a work
    //  around, until the real reason is found for why there is
    //  some EEPROM corruption sometimes
    if(LCD_contrast > 200)
    {
        LCD_contrast = 186;
    }

    if(LCD_tempco > 3)
    {
        LCD_tempco = 1;
    }

    //if(LCD_bias_system > 5)
    //{
        LCD_bias_system = 4;   //just force this for now, until the EEPROM issue is found
    //}


    //If it's in 24 hour format after reading the EEPROM, then
    //  make sure that I override the defaults of 12:00 am when it
    //  starts up.  Make sure that it actually shows 0:00 to start
    if(hours_24)
    {
        current_minutes = 0;
        current_ten_minutes = 0;
        current_hours = 0;
        current_ten_hours = 0;
    }

    SPI_init();
    interrupt_init();
    //timer0_init();
    timer1_init();  //Timer one is the RTC timer
    
    /* Initialize the LCD after the EEPROM variables have been read, 
        because some of those variables contain states that the LCD
        needs to be initialized to */
    LCD_init();

    

    LCD_clear();

    //hours_24 = 1;   //testing to see if I was smart enough to get the 24 hour
                    //  format to work without really even trying...and it does!!! woopwoooop!

    update_clock(1);        //with the frame
    parse_start_time_minutes();
    update_start_time();
    update_runtime_mins();

    LCD_BACKLIGHT = 1;

    while(1)
    {
        /* check whether to start the cycle */
        cycle_start_check();

        /* check which button was pressed, and determine the
            action to take */
        button_check();


        //continuously poll the update clock flag, to see if a minute has
        //  passed and the clock needs to be updated
        if(update)
        {
            parse_time_minutes();
            update_clock(1);    //and draw the frame

        }


        if(start_cycle)
        {
            //There is a ground bounce issue, where I believe the manual
            // switch is being falsely triggered, so do a little
            // debouncing routine here
            if(!MANUAL_SW)
            {
                milliseconds(100);
                if(!MANUAL_SW)
                {
                    man_pressed = 1;
                }
                else
                {
                    man_pressed = 0;
                }
            }
            //The cycle will end if the run minutes counter has reached the set number
            //  of minutes, if someone aborts it with the manual switch, or if
            //  either the main hose or the external hose has been removed
            if(run_minutes_counter >= runtime_minutes_global || man_pressed || HOSE_SW || EXT_HOSE_SW)
            {
                //If it was cancelled using the manual switch, then debounce
                //  the switch, and wait for it to be released
                if(!MANUAL_SW)
                {
                    milliseconds(DEBOUNCE_TIME);
                    while(!MANUAL_SW);
                }
                
                OZAP = 0;
                start_cycle = 0;
                cycle_finished = 1;         //keep track of it being finished, so
                                            //  that I can use that value for other
                                            //  condition checks
                run_minutes_counter = 0;
                RED_LEDS = 0;
            }
            else
            {
                OZAP = 1;       //turn on the ozone and pump
                RED_LEDS = 1;
            }

        } //end if(start_cycle)


        if(cycle_finished)
        {

            if(leds_time_counter != 0)
            {
                YELLOW_LEDS = 1;
                GREEN_LEDS = 0;
            }
            else
            {
                YELLOW_LEDS = 0;
                GREEN_LEDS = 1;
            }
        }


        //When either of the hoses is removed, then reset the cycle, and
        //  turn off all the LEDs
        if(HOSE_SW || EXT_HOSE_SW)
        {
            //All LEDs are off
            YELLOW_LEDS = 0;
            GREEN_LEDS = 0;

            leds_time_counter = 120;    //two hours for yellow LED

            //When the hoses have been removed, and the cycle_finished flag is set,
            //
            if(cycle_finished)
            {
                filter_minutes_count = filter_minutes_count + runtime_minutes_global;
                
                /* Write the low byte of the filter count minutes to EEPROM */
                EEPROM_write_with_check(FILTER_MINUTES_COUNT_L, (filter_minutes_count & 0xFF));

                /* Shift the filter count minutes by 8, and then write the high byte
                   of filter count minutes to EEPROM */
                EEPROM_write_with_check(FILTER_MINUTES_COUNT_H, ((filter_minutes_count >> 8) & 0xFF));

                //After the EEPROM value is written, just double check that the values
                //  were written to what you expect
                EEPROM_value_check(FILTER_MINUTES_COUNT_L, (filter_minutes_count & 0xFF));
                EEPROM_value_check(FILTER_MINUTES_COUNT_H, ((filter_minutes_count >> 8) & 0xFF));

            }

            if(filter_minutes_count >= FILTER_CHANGE_COUNT && cycle_finished)
            {
                filter_change_reminder();
            }

            cycle_finished = 0;     //indicate that a new cycle can be run
        }


    }  //end while(1)
    




    return;
}








void interrupt interrupt_handler(void)
{

    if((INTCONbits.RBIE && INTCONbits.RBIF) || (INTCONbits.INT0IE && INTCONbits.INT0IF) || (INTCON3bits.INT1IE && INTCON3bits.INT1IF) || (INTCON3bits.INT2IE && INTCON3bits.INT2IF))
        {
            //Read the Port B inputs, which will clear the "mismatch condition",
            //  and clear the interrupt
            if(!SW_P || !SW_M || INTCONbits.INT0IF || INTCON3bits.INT1IF || INTCON3bits.INT2IF)
            {
                backlight_seconds_counter = backlight_seconds_count;

                // 0 means that the backlight is always off
                if(backlight_seconds_count == 0)
                {
                    LCD_BACKLIGHT = 0;
                }
                else
                {
                    LCD_BACKLIGHT = 1;
                }
            }


            //Reset the interrupt flags
            INTCONbits.RBIF = 0;
            INTCONbits.INT0IF = 0;
            INTCON3bits.INT1IF = 0;
            INTCON3bits.INT2IF = 0;



        }//end if((INTCONbits.RBIE && INTCONbits.RBIF) || (INTCONbits.INT0IE && INTCONbits.INT0IF) || (INTCON3bits.INT1IE && INTCON3bits.INT1IF) || (INTCON3bits.INT2IE && INTCON3bits.INT2IF))




    if(PIE1bits.TMR1IE && PIR1bits.TMR1IF)
    {
        TMR1H = 0x80;               //Set bit 7 of timer 1 high, so that an
                                    // overflow occurs every second, rather than
                                    // every two seconds

        PIR1bits.TMR1IF = 0;      //reset the interrupt flag

        current_seconds++;          //One more second has now passed
        //current_seconds += 60;

        if(current_seconds == 60)
        {
            current_time_minutes++;
            current_seconds = 0;
            update = 1;

            //if the cycle has been started and is running, then
            //  start counting up the minutes
            if(start_cycle && !cycle_finished)
            {
                run_minutes_counter++;
            }

            // If the cycle is finished, then begin the LED time countdown.
            //  leds_time_counter will start at 120 minutes
            if(cycle_finished && !start_cycle && (leds_time_counter != 0))
            {
                leds_time_counter--;
            }
        } //end if(current_seconds == 60)

        //If there are more seconds to count down, then count them down.
        //  If the seconds count is equal to 255, that means it's always on
        //  If the seconds count is equal to 0, that means it's always off
        if((backlight_seconds_counter != 0 || backlight_seconds_count == 255) && backlight_seconds_count != 0)
        {
            LCD_BACKLIGHT = 1;
            if(backlight_seconds_count != 255)
            {
                backlight_seconds_counter--;
            }
        }
        else
        {
            LCD_BACKLIGHT = 0;
        }


    } //end if(PIE1bits.TMR1IE && PIR1bits.TMR1IF)

        


        


    
    return;


}


